<template>
  <div class="data-table-wrapper">
    <!-- 表格顶部区域：标题、搜索、批量操作等 -->
    <div class="table-header" v-if="title || $slots.tableHeader">
      <h3 class="table-title" v-if="title">{{ title }}</h3>
      <slot name="tableHeader"></slot>
    </div>
    
    <!-- 表格主体 -->
    <div class="table-container">
      <table class="data-table" :class="{ 'striped': striped, 'bordered': bordered }">
        <thead>
          <tr>
            <!-- 选择列 -->
            <th v-if="selectable" class="selection-column">
              <input 
                type="checkbox" 
                :checked="isAllSelected" 
                @click="toggleSelectAll"
                :disabled="loading"
              />
            </th>
            
            <!-- 数据列 -->
            <th 
              v-for="column in columns" 
              :key="column.key" 
              :class="[
                column.align ? `text-${column.align}` : '',
                column.sortable ? 'sortable' : '',
                sortConfig.key === column.key ? `sorted-${sortConfig.order}` : ''
              ]"
              :style="{ width: column.width || 'auto' }"
              @click="column.sortable ? handleSort(column.key) : null"
            >
              <div class="th-content">
                <span>{{ column.title }}</span>
                <span v-if="column.sortable" class="sort-icon">
                  <i :class="getSortIconClass(column.key)"></i>
                </span>
              </div>
            </th>
            
            <!-- 操作列 -->
            <th v-if="$slots.actions" class="actions-column" :style="{ width: actionsWidth || '150px' }">
              操作
            </th>
          </tr>
        </thead>
        
        <tbody>
          <!-- 加载中状态 -->
          <tr v-if="loading" class="loading-row">
            <td :colspan="getColspan()">
              <div class="loading-indicator">
                <i class="fas fa-spinner fa-spin"></i>
                <span>加载中...</span>
              </div>
            </td>
          </tr>
          
          <!-- 空数据状态 -->
          <tr v-else-if="!data || data.length === 0" class="empty-row">
            <td :colspan="getColspan()">
              <div class="empty-indicator">
                <i class="fas fa-inbox"></i>
                <span>{{ emptyText }}</span>
              </div>
            </td>
          </tr>
          
          <!-- 数据行 -->
          <tr 
            v-else
            v-for="(row, index) in paginatedData" 
            :key="row.id || index"
            :class="{ 
              'selected': isRowSelected(row), 
              'clickable': rowClickable 
            }"
            @click="rowClickable ? handleRowClick(row, index) : null"
          >
            <!-- 选择列 -->
            <td v-if="selectable" class="selection-column" @click.stop>
              <input 
                type="checkbox" 
                :checked="isRowSelected(row)" 
                @click="toggleRowSelection(row)"
                :disabled="loading"
              />
            </td>
            
            <!-- 数据列 -->
            <td 
              v-for="column in columns" 
              :key="column.key"
              :class="column.align ? `text-${column.align}` : ''"
            >
              <!-- 使用自定义渲染函数 -->
              <template v-if="column.render">
                <component 
                  :is="column.render" 
                  :row="row" 
                  :value="row[column.key]"
                  :index="index"
                ></component>
              </template>
              
              <!-- 自定义插槽 -->
              <slot 
                v-else-if="$slots[column.key]" 
                :name="column.key" 
                :row="row" 
                :value="row[column.key]"
                :index="index"
              ></slot>
              
              <!-- 默认渲染 -->
              <template v-else>
                {{ formatCellValue(row[column.key], column.format) }}
              </template>
            </td>
            
            <!-- 操作列 -->
            <td v-if="$slots.actions" class="actions-column">
              <slot name="actions" :row="row" :index="index"></slot>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    
    <!-- 分页区域 -->
    <div class="table-footer" v-if="showPagination && data && data.length > 0">
      <div class="pagination-info">
        显示 {{ startIndex + 1 }}-{{ Math.min(endIndex, totalItems) }} 项，共 {{ totalItems }} 项
      </div>
      
      <div class="pagination-controls">
        <button 
          class="page-btn" 
          :disabled="currentPage === 1 || loading" 
          @click="goToPage(1)"
        >
          <i class="fas fa-angle-double-left"></i>
        </button>
        
        <button 
          class="page-btn" 
          :disabled="currentPage === 1 || loading" 
          @click="goToPage(currentPage - 1)"
        >
          <i class="fas fa-angle-left"></i>
        </button>
        
        <div class="page-numbers">
          <button 
            v-for="page in visiblePageNumbers" 
            :key="page"
            class="page-number" 
            :class="{ 'current': page === currentPage }"
            @click="goToPage(page)"
            :disabled="loading"
          >
            {{ page }}
          </button>
        </div>
        
        <button 
          class="page-btn" 
          :disabled="currentPage === totalPages || loading" 
          @click="goToPage(currentPage + 1)"
        >
          <i class="fas fa-angle-right"></i>
        </button>
        
        <button 
          class="page-btn" 
          :disabled="currentPage === totalPages || loading" 
          @click="goToPage(totalPages)"
        >
          <i class="fas fa-angle-double-right"></i>
        </button>
      </div>
      
      <div class="page-size-selector">
        <span>每页显示：</span>
        <select v-model="internalPageSize" :disabled="loading">
          <option v-for="size in pageSizeOptions" :key="size" :value="size">
            {{ size }}
          </option>
        </select>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue';

// 列配置接口
interface TableColumn {
  key: string;           // 数据键名
  title: string;         // 列标题
  align?: 'left' | 'center' | 'right'; // 对齐方式
  width?: string;        // 列宽度
  sortable?: boolean;    // 是否可排序
  format?: string | ((value: any) => string); // 格式化函数
  render?: any;          // 自定义渲染函数
}

// 排序配置接口
interface SortConfig {
  key: string;           // 排序的键名
  order: 'asc' | 'desc'; // 排序方向
}

// 定义组件接收的属性
const props = defineProps({
  // 数据源
  data: {
    type: Array,
    default: () => []
  },
  // 列配置
  columns: {
    type: Array as () => TableColumn[],
    required: true
  },
  // 表格标题
  title: {
    type: String,
    default: ''
  },
  // 是否显示斑马纹
  striped: {
    type: Boolean,
    default: true
  },
  // 是否显示边框
  bordered: {
    type: Boolean,
    default: true
  },
  // 是否可选择行
  selectable: {
    type: Boolean,
    default: false
  },
  // 是否可点击行
  rowClickable: {
    type: Boolean,
    default: false
  },
  // 默认排序字段
  defaultSort: {
    type: Object as () => SortConfig,
    default: () => ({ key: '', order: 'asc' })
  },
  // 操作列宽度
  actionsWidth: {
    type: String,
    default: '150px'
  },
  // 是否显示分页
  showPagination: {
    type: Boolean,
    default: true
  },
  // 当前页码
  page: {
    type: Number,
    default: 1
  },
  // 每页数量
  pageSize: {
    type: Number,
    default: 10
  },
  // 每页可选数量
  pageSizeOptions: {
    type: Array as () => number[],
    default: () => [10, 20, 50, 100]
  },
  // 总数据量（用于远程数据分页）
  totalItems: {
    type: Number,
    default: 0
  },
  // 加载状态
  loading: {
    type: Boolean,
    default: false
  },
  // 空数据提示文本
  emptyText: {
    type: String,
    default: '暂无数据'
  }
});

// 定义事件
const emit = defineEmits([
  'update:page',          // 页码变化
  'update:pageSize',      // 每页数量变化
  'update:sort',          // 排序变化
  'update:selection',     // 选择变化
  'row-click',            // 行点击
  'selection-change'      // 选择变化
]);

// 内部状态
const internalCurrentPage = ref(props.page);
const internalPageSize = ref(props.pageSize);
const sortConfig = ref<SortConfig>({ ...props.defaultSort });
const selectedRows = ref<any[]>([]);

// 监听外部页码变化
watch(() => props.page, (newPage) => {
  internalCurrentPage.value = newPage;
});

// 监听外部每页数量变化
watch(() => props.pageSize, (newPageSize) => {
  internalPageSize.value = newPageSize;
});

// 监听内部页码变化，向上传递
watch(internalCurrentPage, (newPage) => {
  emit('update:page', newPage);
});

// 监听内部每页数量变化，向上传递
watch(internalPageSize, (newPageSize) => {
  emit('update:pageSize', newPageSize);
  // 页码重置为1
  internalCurrentPage.value = 1;
  emit('update:page', 1);
});

// 计算总页数
const totalPages = computed(() => {
  const total = props.totalItems || (props.data?.length || 0);
  return Math.max(1, Math.ceil(total / internalPageSize.value));
});

// 计算当前页数据（本地分页）
const paginatedData = computed(() => {
  if (!props.data) return [];
  
  // 如果提供了总条数，假设是远程分页，直接返回整个数据
  if (props.totalItems > 0) return props.data;
  
  const sortedData = sortData(props.data);
  const start = (internalCurrentPage.value - 1) * internalPageSize.value;
  const end = start + internalPageSize.value;
  return sortedData.slice(start, end);
});

// 计算分页信息
const currentPage = computed(() => internalCurrentPage.value);
const startIndex = computed(() => (currentPage.value - 1) * internalPageSize.value);
const endIndex = computed(() => startIndex.value + internalPageSize.value);
const totalItems = computed(() => props.totalItems || (props.data?.length || 0));

// 计算可见页码
const visiblePageNumbers = computed(() => {
  const total = totalPages.value;
  const current = currentPage.value;
  const maxVisiblePages = 5;
  
  if (total <= maxVisiblePages) {
    return Array.from({ length: total }, (_, i) => i + 1);
  }
  
  let start = Math.max(current - Math.floor(maxVisiblePages / 2), 1);
  let end = start + maxVisiblePages - 1;
  
  if (end > total) {
    end = total;
    start = Math.max(end - maxVisiblePages + 1, 1);
  }
  
  return Array.from({ length: end - start + 1 }, (_, i) => start + i);
});

// 计算是否全选
const isAllSelected = computed(() => {
  if (!props.data || props.data.length === 0) return false;
  return props.data.every(row => isRowSelected(row));
});

// 排序数据
function sortData(data: any[]) {
  if (!sortConfig.value.key || !data || data.length === 0) return [...data];
  
  return [...data].sort((a, b) => {
    const aValue = a[sortConfig.value.key];
    const bValue = b[sortConfig.value.key];
    
    // 如果值相同
    if (aValue === bValue) return 0;
    
    // 如果值为 null 或 undefined，排在最后
    if (aValue == null) return 1;
    if (bValue == null) return -1;
    
    // 根据数据类型排序
    const result = typeof aValue === 'string'
      ? aValue.localeCompare(bValue)
      : aValue - bValue;
    
    return sortConfig.value.order === 'asc' ? result : -result;
  });
}

// 格式化单元格值
function formatCellValue(value: any, format?: string | ((value: any) => string)) {
  if (value === undefined || value === null) return '-';
  
  if (typeof format === 'function') {
    return format(value);
  }
  
  if (format === 'date') {
    return new Date(value).toLocaleDateString();
  }
  
  if (format === 'datetime') {
    return new Date(value).toLocaleString();
  }
  
  if (format === 'currency') {
    return `¥${value.toFixed(2)}`;
  }
  
  return value;
}

// 获取列跨度数
function getColspan() {
  let colspan = props.columns.length;
  if (props.selectable) colspan++;
  if (props.$slots.actions) colspan++;
  return colspan;
}

// 处理排序
function handleSort(key: string) {
  let order: 'asc' | 'desc' = 'asc';
  
  if (sortConfig.value.key === key) {
    // 已经是该列，切换排序方向
    order = sortConfig.value.order === 'asc' ? 'desc' : 'asc';
  }
  
  sortConfig.value = { key, order };
  emit('update:sort', { key, order });
}

// 获取排序图标样式
function getSortIconClass(key: string) {
  if (sortConfig.value.key !== key) {
    return 'fas fa-sort';
  }
  return sortConfig.value.order === 'asc' ? 'fas fa-sort-up' : 'fas fa-sort-down';
}

// 跳转到指定页
function goToPage(page: number) {
  if (page < 1 || page > totalPages.value || page === internalCurrentPage.value) return;
  internalCurrentPage.value = page;
}

// 判断行是否选中
function isRowSelected(row: any) {
  if (!props.selectable) return false;
  if (!row) return false;
  
  const rowId = row.id || JSON.stringify(row);
  return selectedRows.value.some(selectedRow => {
    const selectedId = selectedRow.id || JSON.stringify(selectedRow);
    return selectedId === rowId;
  });
}

// 切换选中所有行
function toggleSelectAll() {
  if (isAllSelected.value) {
    selectedRows.value = [];
  } else {
    selectedRows.value = [...props.data];
  }
  
  emitSelectionChange();
}

// 切换选中行
function toggleRowSelection(row: any) {
  if (isRowSelected(row)) {
    const rowId = row.id || JSON.stringify(row);
    selectedRows.value = selectedRows.value.filter(selectedRow => {
      const selectedId = selectedRow.id || JSON.stringify(selectedRow);
      return selectedId !== rowId;
    });
  } else {
    selectedRows.value.push(row);
  }
  
  emitSelectionChange();
}

// 发送选择变化事件
function emitSelectionChange() {
  emit('update:selection', selectedRows.value);
  emit('selection-change', selectedRows.value);
}

// 处理行点击
function handleRowClick(row: any, index: number) {
  emit('row-click', row, index);
  
  if (props.selectable) {
    toggleRowSelection(row);
  }
}
</script>

<style scoped>
.data-table-wrapper {
  width: 100%;
  border-radius: 8px;
  overflow: hidden;
  background-color: #fff;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

.table-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid #eee;
}

.table-title {
  font-size: 16px;
  font-weight: 600;
  margin: 0;
  color: #333;
}

.table-container {
  width: 100%;
  overflow-x: auto;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  border-spacing: 0;
  font-size: 14px;
}

.data-table.striped tr:nth-child(even) {
  background-color: #f9f9f9;
}

.data-table.bordered {
  border: 1px solid #eee;
}

.data-table.bordered th,
.data-table.bordered td {
  border: 1px solid #eee;
}

.data-table th,
.data-table td {
  padding: 12px 16px;
  text-align: left;
  border-bottom: 1px solid #eee;
}

.data-table th {
  background-color: #f5f5f5;
  font-weight: 600;
  color: #333;
  white-space: nowrap;
  user-select: none;
}

.th-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.selection-column {
  width: 40px;
  text-align: center;
}

.actions-column {
  white-space: nowrap;
  text-align: center;
}

.text-left {
  text-align: left;
}

.text-center {
  text-align: center;
}

.text-right {
  text-align: right;
}

.sortable {
  cursor: pointer;
}

.sortable:hover {
  background-color: #eee;
}

.sort-icon {
  margin-left: 5px;
  color: #999;
}

.sorted-asc .sort-icon,
.sorted-desc .sort-icon {
  color: #1890ff;
}

.loading-row td,
.empty-row td {
  padding: 40px 0;
  text-align: center;
}

.loading-indicator,
.empty-indicator {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: #999;
}

.loading-indicator i,
.empty-indicator i {
  font-size: 24px;
}

.clickable {
  cursor: pointer;
}

.clickable:hover {
  background-color: #f0f0f0;
}

tr.selected {
  background-color: #e6f7ff !important;
}

.table-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-top: 1px solid #eee;
}

.pagination-info {
  font-size: 14px;
  color: #666;
}

.pagination-controls {
  display: flex;
  align-items: center;
  gap: 5px;
}

.page-btn {
  width: 32px;
  height: 32px;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  background-color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: #666;
}

.page-btn:hover:not(:disabled) {
  color: #1890ff;
  border-color: #1890ff;
}

.page-btn:disabled {
  color: #d9d9d9;
  cursor: not-allowed;
}

.page-numbers {
  display: flex;
  gap: 5px;
}

.page-number {
  width: 32px;
  height: 32px;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  background-color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: #666;
}

.page-number:hover:not(.current):not(:disabled) {
  color: #1890ff;
  border-color: #1890ff;
}

.page-number.current {
  color: #fff;
  background-color: #1890ff;
  border-color: #1890ff;
}

.page-number:disabled {
  color: #d9d9d9;
  cursor: not-allowed;
}

.page-size-selector {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 14px;
  color: #666;
}

.page-size-selector select {
  padding: 4px 8px;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  color: #333;
}

@media (max-width: 768px) {
  .table-footer {
    flex-direction: column;
    gap: 10px;
    align-items: flex-start;
  }
  
  .page-size-selector {
    align-self: flex-end;
  }
}
</style> 